package job;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import models.DropboxState;
import models.FileInfo;
import play.Logger;
import play.Play;
import play.db.jpa.Transactional;
import play.jobs.Every;
import play.jobs.Job;
import ru.shop.dropbox.Dropbox;

import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.DropboxAPI.DeltaEntry;
import com.dropbox.client2.DropboxAPI.DeltaPage;
import com.dropbox.client2.DropboxAPI.DropboxInputStream;
import com.dropbox.client2.DropboxAPI.Entry;
import com.dropbox.client2.DropboxAPI.ThumbFormat;
import com.dropbox.client2.DropboxAPI.ThumbSize;
import com.dropbox.client2.exception.DropboxException;

@Every(value = "1mn")
public class DropboxSync extends Job {
	private String thumbnailPath = Play.configuration.getProperty("shop.dropbox.thumbnail.path", "_th");
	private String targetPath = Play.configuration.getProperty("shop.dropbox.target.path", "");

	private DropboxState state;

	@Override
	public void doJob() throws Exception {
		Logger.info("Dropbox job inprogress...");
		state = DropboxState.findById(new Long(1));
		for (int i = 0; i < 5; i++) {
			if (doDelta().hasMore != true)
				break;
		}
		Logger.info("Dropbox job finished.");
	}

	@Transactional
	private DeltaPage<Entry> doDelta() throws DropboxException, Exception {
		DeltaPage<Entry> delta = Dropbox.clientCommon.delta(state.cursor);
		for (DeltaEntry<Entry> entry : delta.entries) {
			Entry entryMeta = entry.metadata;
			if (isNewFile(entryMeta)) {
				// copy thumbnails
				for (ThumbSize thumbSize : ThumbSize.values()) {
					copyThumbnail(thumbSize, entryMeta);
				}
				// copy source
				copyFile(entryMeta);

				FileInfo log = new FileInfo(state.number.toString(), entry.lcPath);
				if (!log.create()) {
					throw new Exception("Cannot create:" + log);
				}
				state.number = state.number + 1;
			} else if (isDeleted(entryMeta)) {
				Logger.info("- " + entry.lcPath);
				FileInfo fileInf = FileInfo.find("byLcPath", entry.lcPath).first();
				if (fileInf != null) {
					fileInf.deleted = true;
					fileInf.save();
				}
			} else {
				Logger.info("Unknown file or folder: " + entry.lcPath);
			}
		}

		state.cursor = delta.cursor;
		state.updated = new Date();
		state.save();
		return delta;
	}

	private void copyFile(Entry entryMeta) throws Exception {
		String uniqueFileName = generateUniqueFileName(entryMeta.fileName());
		DropboxInputStream dis = Dropbox.clientCommon.getFileStream(entryMeta.path, null);
		Dropbox.clientPriv.putFileOverwrite(String.format("%s/%s", targetPath, uniqueFileName), dis, dis.getFileInfo().getFileSize(), null);
		try {
			dis.close();
		} catch (Exception e) {/* quite */
		}
	}

	private void copyThumbnail(ThumbSize thSize, Entry entryMeta) throws DropboxException {
		DropboxInputStream dis = Dropbox.clientCommon.getThumbnailStream(entryMeta.path, thSize, ThumbFormat.PNG);
		Dropbox.clientPriv.putFileOverwrite(String.format("%s/" + thSize.toAPISize() + "/%s." + ThumbFormat.PNG.toString().toLowerCase(), thumbnailPath,
				state.number), dis, dis.getFileInfo().getFileSize(), null);
		try {
			dis.close();
		} catch (Exception e) {/* quite */
		}
	}

	private String generateUniqueFileName(String fileName) throws Exception {
		return state.number + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
	}

	private boolean isDeleted(Entry entryMeta) {
		return entryMeta == null || entryMeta.isDeleted;
	}

	private boolean isNewFile(Entry entryMeta) {
		return entryMeta != null && !entryMeta.isDir && !entryMeta.isDeleted && entryMeta.bytes <= DropboxAPI.MAX_UPLOAD_SIZE;
	}
}
